#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>

#include "imbus_internal.h"
#include "im_connection_unix.h"
#include "im_address_unix.h"
#include "im_io_unix.h"

IMConnection*
im_connection_unix_new_connect (const IMChar *address, IMIOError *error)
{
    IMAddressUnix *addr = IM_ADDRESS_UNIX(im_address_unix_new (address));
    _im_assert (addr);

    if (im_address_valid (IM_ADDRESS(addr))) {
        IMIOChannel *channel;
        struct sockaddr *sock_addr;
        socklen_t sock_len;
        IMInt fd = -1;
        switch (im_address_unix_get_type (addr)) {
            case IM_ADDRESS_UNIX_LOCAL:
                fd = socket (PF_UNIX, SOCK_STREAM, 0);
                break;
            case IM_ADDRESS_UNIX_INET:
                fd = socket (PF_INET, SOCK_STREAM, 0);
                break;
            default:
                im_object_unref (addr);
                return 0;
        }

        if (fd < 0) {
            if (error) *error = im_io_channel_error_from_errno (errno);
            im_object_unref (addr);
            return 0;
        }

        sock_addr = (struct sockaddr*)im_address_unix_get_data (addr);
        sock_len = im_address_unix_get_data_length (addr);
        if (connect (fd, sock_addr, sock_len) != 0) {
            close (fd);
            if (error) *error = im_io_channel_error_from_errno (errno);
            im_object_unref (addr);
            return 0;
        }

        channel = im_io_channel_unix_new (fd);
        _im_assert (channel);
        im_object_unref (addr);
        return im_connection_new (channel);
    }
    im_object_unref (addr);
    return 0;
}

/*
vi:ts=4:nowrap:ai:expandtab
*/
